from django.db.models import Q
from rest_framework import viewsets, filters, status
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView
from elasticsearch import Elasticsearch
from django.http import JsonResponse
import traceback
import logging
import json
import os
import base64
import requests
from django.conf import settings
from rest_framework.parsers import JSONParser
from django.views.decorators.csrf import csrf_exempt
import dashscope
from dashscope import Generation
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import DashScopeEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.schema import Document
import asyncio
from django.shortcuts import render
from langchain.tools import Tool
from langchain.agents import AgentType, initialize_agent
from langchain.llms.base import BaseLLM
from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain_community.chat_models import QianfanChatEndpoint

from apps.background.models import MedicalArticle
from apps.background.serializers import MedicalArticleSerializer
from apps.background.views import Page

logger = logging.getLogger('essay')

# 设置通义千问API密钥
import os
dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")  # 从环境变量获取API密钥

# 向量数据库路径
VECTOR_DB_PATH = os.path.join('uploads', 'vector_db')

# 初始化向量数据库
def initialize_vector_db():
    """从Word文档或文本文件初始化医疗向量数据库"""
    try:
        import os  # 确保os模块在函数内可用
        logger.info("开始初始化向量数据库...")
        
        # 指定文件路径 - 支持多种格式
        doc_path = os.path.join(settings.MEDIA_ROOT, 'sj', '20中病例.doc')
        txt_path = os.path.join(settings.MEDIA_ROOT, 'sj', '20中病例.txt')
        
        # 首先检查是否存在文本文件版本
        if os.path.exists(txt_path):
            logger.info(f"找到文本文件: {txt_path}")
            try:
                with open(txt_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                logger.info(f"成功从文本文件中读取内容，长度: {len(content)}")
            except Exception as e:
                logger.error(f"读取文本文件失败: {str(e)}")
                return False, f"读取文本文件失败: {str(e)}"
        # 如果没有文本文件，尝试处理Word文档
        elif os.path.exists(doc_path):
            logger.info(f"找到Word文档: {doc_path}")
            
            # 提取Word文档内容
            content = ""
            try:
                # 简化处理方法，直接尝试使用textract
                try:
                    import textract
                    content = textract.process(doc_path).decode('utf-8', errors='ignore')
                    logger.info("使用textract成功提取Word文档内容")
                    
                    # 如果成功提取，保存一份文本版本以便将来使用
                    try:
                        with open(txt_path, 'w', encoding='utf-8') as f:
                            f.write(content)
                        logger.info(f"已将内容保存为文本文件: {txt_path}")
                    except Exception as save_err:
                        logger.warning(f"保存文本文件失败: {str(save_err)}")
                except Exception as e:
                    logger.error(f"使用textract处理Word文档失败: {str(e)}")
                    
                    # 尝试使用pywin32
                    try:
                        import win32com.client
                        word = win32com.client.Dispatch("Word.Application")
                        word.visible = False
                        doc = word.Documents.Open(os.path.abspath(doc_path))
                        content = doc.Content.Text
                        doc.Close()
                        word.Quit()
                        logger.info("使用win32com成功提取Word文档内容")
                        
                        # 保存文本版本
                        try:
                            with open(txt_path, 'w', encoding='utf-8') as f:
                                f.write(content)
                            logger.info(f"已将内容保存为文本文件: {txt_path}")
                        except Exception as save_err:
                            logger.warning(f"保存文本文件失败: {str(save_err)}")
                    except Exception as win_err:
                        logger.error(f"使用win32com处理Word文档失败: {str(win_err)}")
                        return False, f"无法提取Word文档内容，请手动将文档内容保存为文本文件"
            except Exception as e:
                logger.error(f"提取Word文档内容失败: {str(e)}")
                return False, f"提取Word文档内容失败: {str(e)}"
        else:
            logger.error(f"文件不存在: 既没有找到 {doc_path} 也没有找到 {txt_path}")
            return False, f"文件不存在: 请确保文档文件位于正确路径"
        
        # 检查内容有效性
        if not content or len(content) < 100:
            return False, "提取的内容太短或无效"
        
        logger.info(f"成功提取文档内容，长度: {len(content)}")
        
        # 文本分割器
        text_splitter = CharacterTextSplitter(
            separator="\n\n",
            chunk_size=1000,  # 确保不超过2048字符的限制
            chunk_overlap=100,
            length_function=len
        )
        
        # 分割文本
        chunks = text_splitter.split_text(content)
        logger.info(f"文本已分割为 {len(chunks)} 个块")
        
        # 检查每个块的大小，确保不超过限制
        valid_chunks = []
        for i, chunk in enumerate(chunks):
            if len(chunk) <= 2000:  # 留一些余量
                valid_chunks.append(chunk)
            else:
                # 如果块太大，进一步分割
                logger.warning(f"块 {i} 太大 ({len(chunk)} 字符)，进一步分割")
                smaller_splitter = CharacterTextSplitter(
                    separator="\n",
                    chunk_size=1000,
                    chunk_overlap=50,
                    length_function=len
                )
                smaller_chunks = smaller_splitter.split_text(chunk)
                for sc in smaller_chunks:
                    if len(sc) <= 2000:
                        valid_chunks.append(sc)
                    else:
                        # 如果还是太大，截断
                        logger.warning(f"截断过大的文本块 ({len(sc)} 字符)")
                        valid_chunks.append(sc[:2000])
        
        logger.info(f"处理后共有 {len(valid_chunks)} 个有效文本块")
        
        # 创建文档对象
        documents = []
        for i, chunk in enumerate(valid_chunks):
            # 构建元数据
            metadata = {
                "chunk": i,
                "source": "20中病例"
            }
            
            # 创建文档对象
            doc = Document(
                page_content=chunk,
                metadata=metadata
            )
            documents.append(doc)
        
        logger.info(f"成功创建 {len(documents)} 个文档对象")
        
        # 创建向量数据库
        try:
            embeddings = DashScopeEmbeddings(model="text-embedding-v2")
            vector_db = FAISS.from_documents(documents, embeddings)
            
            # 保存向量数据库到本地
            os.makedirs(VECTOR_DB_PATH, exist_ok=True)
            vector_db.save_local(VECTOR_DB_PATH)
            
            return True, f"向量数据库初始化成功，共 {len(documents)} 个文档片段"
        except Exception as e:
            logger.error(f"创建向量数据库失败: {str(e)}")
            return False, f"创建向量数据库失败: {str(e)}"
            
    except Exception as e:
        logger.error(f"向量数据库初始化失败: {str(e)}")
        return False, f"向量数据库初始化失败: {str(e)}"

# 查询向量数据库
def query_vector_db(query, top_k=3):
    """查询向量数据库"""
    try:
        # 清理查询，移除零宽空格等不可见字符
        query = query.replace('\u200b', '').strip()
        
        # 记录查询内容
        logger.info(f"向量数据库查询: {query}")
        
        # 检查向量数据库路径是否存在
        if not os.path.exists(VECTOR_DB_PATH):
            logger.error(f"向量数据库路径不存在: {VECTOR_DB_PATH}")
            return False, "向量数据库尚未初始化，请先调用初始化接口"
        
        # 加载向量数据库
        embeddings = DashScopeEmbeddings(model="text-embedding-v2")
        vector_db = FAISS.load_local(VECTOR_DB_PATH, embeddings, allow_dangerous_deserialization=True)
        logger.info(f"向量数据库加载成功，开始查询...")
        
        # 查询相似文档
        docs = vector_db.similarity_search(query, k=top_k)
        
        # 在查询后添加日志
        logger.info(f"向量查询返回文档数量: {len(docs)}")
        
        # 记录文档内容预览
        for i, doc in enumerate(docs):
            content_preview = doc.page_content[:50] + "..." if len(doc.page_content) > 50 else doc.page_content
            logger.info(f"文档{i+1}内容预览: {content_preview}")
        
        return True, docs
    except Exception as e:
        logger.error(f"查询向量数据库失败: {str(e)}")
        return False, f"查询向量数据库失败: {str(e)}"

# Agent工具1: 症状诊断工具
def symptom_diagnosis_tool(symptoms):
    """根据症状查询可能的疾病"""
    try:
        # 构建症状查询
        symptom_query = f"症状: {symptoms} 可能是什么疾病？"
        logger.info(f"症状查询: {symptom_query}")
        
        # 查询向量数据库
        success, docs = query_vector_db(symptom_query)
        if not success:
            return "向量数据库查询失败，请确保已初始化向量数据库"
        
        # 检查文档有效性
        if not docs:
            return "没有找到相关的医疗信息"
        
        # 构建上下文
        context = ""
        for i, doc in enumerate(docs):
            context += f"文档{i+1}:\n{doc.page_content}\n\n"
        
        # 构建提示词
        prompt = f"""你是一个专业的医疗助手，请根据提供的医疗文档回答用户的问题。
        
用户描述的症状: {symptoms}

参考文档:
{context}

请根据这些症状和参考文档，分析可能的疾病，并给出专业的建议。如果参考文档中有相关信息，请详细解释。
如果无法确定具体疾病，请给出一些可能性并建议就医。请确保回答不超过200字。
"""
        
        # 调用通义千问API
        response = Generation.call(
            model="qwen-max",
            prompt=prompt,
            result_format='message',
            max_tokens=300,
        )
        
        if response.status_code == 200:
            answer = response.output.choices[0].message.content
            return answer
        else:
            return "API调用失败，无法提供诊断信息"
            
    except Exception as e:
        logger.error(f"症状诊断工具失败: {str(e)}")
        return f"症状诊断失败: {str(e)}"

# Agent工具2: 禁忌查询工具
def restriction_query_tool(disease):
    """查询疾病的禁忌事项"""
    try:
        # 构建禁忌查询
        restriction_query = f"{disease} 患者有哪些禁忌？不能做什么？不能吃什么？"
        logger.info(f"禁忌查询: {restriction_query}")
        
        # 查询向量数据库
        success, docs = query_vector_db(restriction_query)
        if not success:
            return "向量数据库查询失败，请确保已初始化向量数据库"
        
        # 检查文档有效性
        if not docs:
            return "没有找到相关的医疗信息"
        
        # 构建上下文
        context = ""
        for i, doc in enumerate(docs):
            context += f"文档{i+1}:\n{doc.page_content}\n\n"
        
        # 构建提示词
        prompt = f"""你是一个专业的医疗助手，请根据提供的医疗文档回答用户的问题。
        
用户查询的疾病: {disease}

参考文档:
{context}

请根据参考文档，详细说明该疾病患者的禁忌事项，包括不能做什么和不能吃什么。
如果参考文档中有相关信息，请详细解释。如果没有找到具体禁忌信息，请给出一些通用建议。请确保回答不超过200字。
"""
        
        # 调用通义千问API
        response = Generation.call(
            model="qwen-max",
            prompt=prompt,
            result_format='message',
            max_tokens=300,
        )
        
        if response.status_code == 200:
            answer = response.output.choices[0].message.content
            return answer
        else:
            return "API调用失败，无法提供禁忌信息"
            
    except Exception as e:
        logger.error(f"禁忌查询工具失败: {str(e)}")
        return f"禁忌查询失败: {str(e)}"

@api_view(['POST'])
@permission_classes([AllowAny])
@csrf_exempt
def initialize_medical_vector_db(request):
    """初始化医疗病例向量数据库"""
    try:
        success, message = initialize_vector_db()
        
        if success:
            return JsonResponse({
                'status': 'success',
                'message': message
            })
        else:
            logger.error(f"向量数据库初始化失败: {message}")
            return JsonResponse({
                'status': 'error',
                'message': message
            }, status=500)
    except Exception as e:
        import traceback
        error_traceback = traceback.format_exc()
        logger.error(f"向量数据库初始化异常: {str(e)}\n{error_traceback}")
        return JsonResponse({
            'status': 'error',
            'message': f"向量数据库初始化异常: {str(e)}",
            'traceback': error_traceback
        }, status=500)

@api_view(['POST'])
@permission_classes([AllowAny])
@csrf_exempt
def ai_medical_assistant(request):
    """智能医疗助手接口 - 使用Agent模式"""
    try:
        # 解析请求数据
        data = JSONParser().parse(request)
        query = data.get('query', '')
        
        # 清理文本，移除零宽空格等不可见字符
        query = query.replace('\u200b', '').strip()
        
        if not query:
            return JsonResponse({
                'status': 'error',
                'message': '请提供问题内容'
            }, status=400)
        
        # 记录查询
        logger.info(f"AI医疗助手收到问题: {query}")
        
        # 创建工具列表
        tools = [
            Tool(
                name="症状诊断",
                func=symptom_diagnosis_tool,
                description="当用户描述身体症状、不适或疼痛时使用此工具，用于分析可能的疾病。例如：'发烧、咳嗽'、'头痛、恶心'、'胸闷气短'等。"
            ),
            Tool(
                name="禁忌查询",
                func=restriction_query_tool,
                description="当用户询问某种疾病患者的禁忌事项、不能做什么或不能吃什么时使用此工具。例如：'糖尿病不能吃什么'、'高血压患者禁忌'等。"
            )
        ]
        
        # 构建工具选择提示词
        tool_selection_prompt = f"""你是一个医疗助手，需要根据用户的问题选择合适的工具来回答。
        
用户问题: {query}

请仔细分析用户问题的类型，并选择最合适的工具:
1. 如果用户描述的是身体症状、不适或疼痛，请使用"症状诊断"工具。
2. 如果用户询问某种疾病患者的禁忌事项、不能做什么或不能吃什么，请使用"禁忌查询"工具。

请只回答应该使用的工具名称，不要添加任何其他内容。
"""
        
        # 调用通义千问API来选择工具
        response = Generation.call(
            model="qwen-max",
            prompt=tool_selection_prompt,
            result_format='message',
            max_tokens=50,
        )
        
        if response.status_code != 200:
            return JsonResponse({
                'status': 'error',
                'message': f"工具选择API调用失败"
            }, status=500)
        
        # 获取选择的工具
        tool_response = response.output.choices[0].message.content.strip()
        logger.info(f"工具选择结果: {tool_response}")
        
        # 根据选择的工具执行查询
        if "症状诊断" in tool_response:
            logger.info("使用症状诊断工具")
            answer = symptom_diagnosis_tool(query)
            query_type = "symptoms"
        elif "禁忌查询" in tool_response:
            logger.info("使用禁忌查询工具")
            answer = restriction_query_tool(query)
            query_type = "restrictions"
        else:
            # 默认使用症状诊断工具
            logger.info("未明确选择工具，默认使用症状诊断工具")
            answer = symptom_diagnosis_tool(query)
            query_type = "symptoms"
        
        logger.info(f"AI回答成功，回答长度: {len(answer)}")
        
        return JsonResponse({
            'status': 'success',
            'question': query,
            'query_type': query_type,
            'answer': answer
        })
            
    except Exception as e:
        logger.error(f"AI医疗助手处理失败: {str(e)}")
        return JsonResponse({
            'status': 'error',
            'message': f"处理失败: {str(e)}",
            'traceback': traceback.format_exc()
        }, status=500)

class MedicalArticleViewSet(viewsets.ModelViewSet):
    """医疗文章视图集，提供文章的增删改查、过滤、搜索、点赞、浏览等功能"""
    queryset = MedicalArticle.objects.all()
    serializer_class = MedicalArticleSerializer
    pagination_class = Page
    filter_backends = [filters.SearchFilter]
    search_fields = ['title', 'content', 'tags']
    
    def get_queryset(self):
        """
        获取文章列表，支持按科室、标签、状态过滤。
        - department_id: 按科室过滤
        - tag: 按标签过滤
        - status: 文章状态（默认只显示已发布）
        """
        queryset = super().get_queryset()
        
        # 支持按部门和标签过滤
        department_id = self.request.query_params.get('department_id')
        tag = self.request.query_params.get('tag')
        status_value = self.request.query_params.get('status', 'published')  # 默认只显示已发布
        
        if department_id:
            queryset = queryset.filter(department_id=department_id)
        if tag:
            queryset = queryset.filter(tags__contains=tag)
        if status_value:
            queryset = queryset.filter(status=status_value)
            
        return queryset
    
    @action(detail=True, methods=['post'])
    def view(self, request, pk=None):
        """
        增加文章浏览次数
        :param pk: 文章主键ID
        :return: 新的浏览次数
        """
        article = self.get_object()
        article.view_count += 1
        article.save(update_fields=['view_count'])
        return Response({'status': 'success', 'view_count': article.view_count})
    
    @action(detail=True, methods=['post'])
    def like(self, request, pk=None):
        """
        文章点赞
        :param pk: 文章主键ID
        :return: 新的点赞数
        """
        article = self.get_object()
        article.like_count += 1
        article.save(update_fields=['like_count'])
        return Response({'status': 'success', 'like_count': article.like_count})

class ArticleRecommendationView(APIView):
    """
    文章推荐视图，提供热门和最新文章推荐
    """
    
    def get(self, request):
        """
        获取推荐文章列表：
        - 热门文章：浏览量最高的10篇
        - 最新文章：最近发布的5篇
        :return: 包含热门和最新文章的序列化数据
        """
        # 获取热门文章（浏览量最高的10篇）
        hot_articles = MedicalArticle.objects.filter(
            status='published'
        ).order_by('-view_count')[:10]
        
        # 获取最新文章（最近发布的5篇）
        latest_articles = MedicalArticle.objects.filter(
            status='published'
        ).order_by('-created_at')[:5]
        
        # 返回结果
        hot_serializer = MedicalArticleSerializer(hot_articles, many=True)
        latest_serializer = MedicalArticleSerializer(latest_articles, many=True)
        
        return Response({
            'hot_articles': hot_serializer.data,
            'latest_articles': latest_serializer.data
        })

class ArticleDetailView(APIView):
    """
    文章详情视图，获取单篇文章详情及相关文章推荐
    """
    
    def get(self, request, article_id):
        """
        获取文章详情，并自动增加浏览次数，同时推荐相关文章（同科室或同标签）
        :param article_id: 文章ID
        :return: 文章详情及相关文章
        """
        try:
            article = MedicalArticle.objects.get(id=article_id)
            serializer = MedicalArticleSerializer(article)
            
            # 增加浏览次数
            article.view_count += 1
            article.save(update_fields=['view_count'])
            
            # 获取相关文章（同一科室或相同标签）
            related_articles = MedicalArticle.objects.filter(
                Q(department=article.department) | Q(tags__contains=article.tags.split(',')[0] if article.tags else ''),
                status='published'
            ).exclude(id=article_id).order_by('-created_at')[:5]
            
            related_serializer = MedicalArticleSerializer(related_articles, many=True)
            
            return Response({
                'article': serializer.data,
                'related_articles': related_serializer.data
            })
        except MedicalArticle.DoesNotExist:
            return Response({'error': '文章不存在'}, status=status.HTTP_404_NOT_FOUND)

class ArticleRecommendationAPIView(APIView):
    """
    基于Elasticsearch的文章推荐API视图，支持关键词和科室推荐
    """
    
    def get(self, request):
        """
        获取文章推荐（优先从ES获取，失败则回退数据库）
        - keyword: 关键词
        - department_id: 科室ID
        :return: 推荐文章列表
        """
        try:
            # 从ES中获取推荐文章
            from background.es_utils.api import get_article_recommendations
            keyword = request.query_params.get('keyword', '')
            department_id = request.query_params.get('department_id')
            
            recommendations = get_article_recommendations(keyword, department_id)
            return Response(recommendations)
        except Exception as e:
            # 如果ES出错，回退到数据库查询
            articles = MedicalArticle.objects.filter(
                status='published'
            ).order_by('-created_at')[:10]
            
            serializer = MedicalArticleSerializer(articles, many=True)
            return Response(serializer.data)

@api_view(['GET'])
@permission_classes([AllowAny])
def import_articles_to_es(request):
    """
    将所有文章导入/同步到Elasticsearch的API端点。
    - 先删除原有索引，再重建并导入所有文章。
    - 用于全文检索和推荐。
    :return: 导入结果和数量
    """
    try:
        # 创建ES连接
        es = Elasticsearch('http://localhost:9200/')
        index_name = 'medical_articles'
        
        # 每次都重建索引，确保数据一致性
        if es.indices.exists(index=index_name):
            es.indices.delete(index=index_name)
            
        # 创建索引配置
        index_settings = {
            "settings": {"number_of_shards": 1, "number_of_replicas": 0},
            "mappings": {
                "properties": {
                    "id": {"type": "keyword"},
                    "title": {"type": "text", "analyzer": "standard"},
                    "content": {"type": "text", "analyzer": "standard"},
                    "author": {"type": "text"},
                    "department_name": {"type": "keyword"},
                    "tags": {"type": "text", "analyzer": "standard"},
                    "status": {"type": "keyword"},
                    "view_count": {"type": "integer"},
                    "like_count": {"type": "integer"},
                    "created_at": {"type": "date"},
                    "updated_at": {"type": "date"}
                }
            }
        }
        
        # 创建索引
        es.indices.create(index=index_name, body=index_settings)
        
        # 查询所有文章
        articles = MedicalArticle.objects.select_related('department').all()
        count = articles.count()
        
        # 导入数据到ES
        bulk_data = []
        for article in articles:
            # 构建索引操作和文档数据
            bulk_data.append({"index": {"_index": index_name, "_id": str(article.id)}})
            bulk_data.append({
                "id": article.id,
                "title": article.title,
                "content": article.content,
                "author": article.author,
                "department_name": article.department.name if article.department else "",
                "tags": article.tags,
                "status": article.status,
                "view_count": article.view_count,
                "like_count": article.like_count,
                "created_at": article.created_at.isoformat() if article.created_at else None,
                "updated_at": article.updated_at.isoformat() if article.updated_at else None
            })
        
        if bulk_data:
            # 执行批量导入
            es.bulk(body=bulk_data, refresh=True)
        
        return JsonResponse({
            'status': 'success',
            'message': f'成功导入/同步 {count} 篇文章到Elasticsearch',
            'index_name': index_name
        })
        
    except Exception as e:
        import traceback
        return JsonResponse({
            'status': 'error',
            'message': f'导入失败: {str(e)}',
            'traceback': traceback.format_exc()
        }, status=500)


@api_view(['GET'])
@permission_classes([AllowAny])
def search_articles(request):
    """
    基于Elasticsearch的文章搜索API。
    - query: 搜索关键词
    - 支持高亮显示和模糊匹配
    :return: 搜索结果列表
    """
    query = request.GET.get('query')
    if not query:
        return JsonResponse({
            'status': 'error',
            'message': '请提供搜索关键词'
        }, status=400)
    
    try:
        # 创建ES连接
        es = Elasticsearch('http://localhost:9200/')
        
        # 检查索引是否存在
        index_name = 'medical_articles'
        if not es.indices.exists(index=index_name):
            return JsonResponse({
                'status': 'error',
                'message': 'ES索引不存在，请先调用导入API同步数据'
            }, status=500)
        
        # 构建搜索查询
        search_body = {
            "query": {
                "multi_match": {
                    "query": query,
                    "fields": ["title^3", "content^2", "tags"],
                    "fuzziness": "AUTO"
                }
            },
            "highlight": {
                "fields": {
                    "title": {},
                    "content": {}
                }
            }
        }
        
        # 执行搜索
        response = es.search(
            index=index_name,
            body=search_body,
            size=20
        )
        
        # 处理结果
        hits = response["hits"]["hits"]
        results = []
        
        for hit in hits:
            source = hit["_source"]
            
            # 获取高亮内容或使用原内容
            highlighted_content = ""
            if "highlight" in hit:
                if "content" in hit["highlight"]:
                    highlighted_content = "...".join(hit["highlight"]["content"])
                elif "title" in hit["highlight"]:
                    highlighted_content = "...".join(hit["highlight"]["title"])
                    
            if not highlighted_content and "content" in source:
                # 如果没有高亮，取前100个字符
                highlighted_content = source["content"][:100] + "..." if len(source["content"]) > 100 else source["content"]
                
            # 构建结果数据
            article_dict = {
                'id': source.get("id"),
                'title': source.get("title"),
                'author': source.get("author"),
                'department': source.get("department_name"),
                'tags': source.get("tags"),
                'view_count': source.get("view_count"),
                'like_count': source.get("like_count"),
                'created_at': source.get("created_at"),
                'content_preview': highlighted_content,
                'content': source.get("content"),
                'score': hit["_score"]
            }
            
            results.append(article_dict)
        
        return JsonResponse({
            'status': 'success',
            'count': response["hits"]["total"]["value"] if "value" in response["hits"]["total"] else response["hits"]["total"],
            'results': results
        })
        
    except Exception as e:
        import traceback
        return JsonResponse({
            'status': 'error',
            'message': f'搜索失败: {str(e)}',
            'traceback': traceback.format_exc()
        }, status=500)